# encoding: UTF-8

'''
vn.ksgold的gateway接入

金仕达黄金接口在用户登录后，并不提供之前的Order和Trade数据主动推送，
而是需要用户自行查询，因此API里做了初始化后的查询设计。
'''

import os
import json
import time

from vnksgoldtd import TdApi
from ksgoldDataType import *
from vtGateway import *

# 以下类型映射参考的是原生API里的Constant.h

# 方向类型映射
directionMap = {}
directionMap[DIRECTION_LONG] = '0'
directionMap[DIRECTION_SHORT] = '1'
directionMapReverse = {v: k for k, v in directionMap.items()}

# 开平类型映射
offsetMap = {}
offsetMap[OFFSET_OPEN] = '0'
offsetMap[OFFSET_CLOSE] = '1'
offsetMapReverse = {v:k for k,v in offsetMap.items()}


########################################################################
class KsgoldGateway(VtGateway):
	"""金仕达黄金接口"""

	#----------------------------------------------------------------------
	def __init__(self, eventEngine, gatewayName='KSGOLD'):
		"""Constructor"""
		super(KsgoldGateway, self).__init__(eventEngine, gatewayName)

		self.tdApi = KsgoldTdApi(self)  # 黄金接口只有交易API
		self.tdConnected = False		# 交易API连接状态
		self.qryEnabled = False		 # 是否要启动循环查询
		
		self.orderInited = False		# 委托初始化查询
		self.tradeInited = False		# 成交初始化查询
		
	#----------------------------------------------------------------------
	def connect(self):
		"""连接"""
		# 载入json文件
		fileName = self.gatewayName + '_connect.json'
		fileName = os.getcwd() + '/ksgoldGateway/' + fileName
		
		try:
			f = file(fileName)
		except IOError:
			log = VtLogData()
			log.gatewayName = self.gatewayName
			log.logContent = u'读取连接配置出错，请检查'
			self.onLog(log)
			return
		
		# 解析json文件
		setting = json.load(f)
		try:
			accountID = str(setting['accountID'])
			password = str(setting['password'])
			address = str(setting['address'])
		except KeyError:
			log = VtLogData()
			log.gatewayName = self.gatewayName
			log.logContent = u'连接配置缺少字段，请检查'
			self.onLog(log)
			return
		
		# 创建行情和交易接口对象
		self.tdApi.connect(accountID, password, address)
		
		# 初始化并启动查询
		self.initQuery()
	
	#----------------------------------------------------------------------
	def subscribe(self, subscribeReq):
		"""订阅行情"""
		self.tdApi.subscribe(subscribeReq)
		
	#----------------------------------------------------------------------
	def sendOrder(self, orderReq):
		"""发单"""
		return self.tdApi.sendOrder(orderReq)
		
	#----------------------------------------------------------------------
	def cancelOrder(self, cancelOrderReq):
		"""撤单"""
		self.tdApi.cancelOrder(cancelOrderReq)
		
	#----------------------------------------------------------------------
	def qryAccount(self):
		"""查询账户资金"""
		self.tdApi.qryAccount()
		
	#----------------------------------------------------------------------
	def qryPosition(self):
		"""查询持仓"""
		self.tdApi.qryPosition()
		
	#----------------------------------------------------------------------
	def close(self):
		"""关闭"""
		if self.tdConnected:
			self.tdApi.close()
		
	#----------------------------------------------------------------------
	def initQuery(self):
		"""初始化连续查询"""
		# 需要循环的查询函数列表
		self.qryFunctionList = [self.qryAccount, self.qryPosition]
		
		self.qryCount = 0		   # 查询触发倒计时
		self.qryTrigger = 2		 # 查询触发点
		self.qryNextFunction = 0	# 上次运行的查询函数索引
	
	#----------------------------------------------------------------------
	def query(self, event):
		"""注册到事件处理引擎上的查询函数"""
		self.qryCount += 1
		
		if self.qryCount > self.qryTrigger:
			# 清空倒计时
			self.qryCount = 0
			
			# 如果尚未完成委托查询则先查询委托
			if not self.orderInited:
				self.tdApi.getOrder()
			# 然后如果未完成成交查询则再查询成交
			elif not self.tradeInited:
				self.tdApi.getTrade()
			else:
				# 执行查询函数
				function = self.qryFunctionList[self.qryNextFunction]
				function()
				
				# 计算下次查询函数的索引，如果超过了列表长度，则重新设为0
				self.qryNextFunction += 1
				if self.qryNextFunction == len(self.qryFunctionList):
					self.qryNextFunction = 0
	
	#----------------------------------------------------------------------
	def startQuery(self):
		"""启动连续查询"""
		if self.qryEnabled:
			self.eventEngine.register(EVENT_TIMER, self.query)
	
	#----------------------------------------------------------------------
	def setQryEnabled(self, qryEnabled):
		"""设置是否要启动循环查询"""
		self.qryEnabled = qryEnabled
	

########################################################################
class KsgoldTdApi(TdApi):
	"""金仕达黄金交易API实现"""
	
	#----------------------------------------------------------------------
	def __init__(self, gateway):
		"""API对象的初始化函数"""
		super(KsgoldTdApi, self).__init__()
		
		self.gateway = gateway				  # gateway对象
		self.gatewayName = gateway.gatewayName  # gateway对象名称
		
		self.reqID = EMPTY_INT			  # 操作请求编号
		self.orderRef = EMPTY_INT		   # 订单编号
		
		self.connectionStatus = False	   # 连接状态
		self.loginStatus = False			# 登录状态
		
		self.accountID = EMPTY_STRING	   # 账号
		self.password = EMPTY_STRING		# 密码
		self.memberID = EMPTY_STRING		# 会员代码（应该是银行）
		self.address = EMPTY_STRING		 # 服务器地址
		
		self.seatID = EMPTY_STRING;		 # 席位号
		self.tradeCode = EMPTY_STRING	   # 交易编码
		
		self.subscribedSymbols = set()	  # 已订阅合约代码
		
		self.orderDict = {}				 # 委托字典，用于缓存委托对象，key为整数
		
		# 循环登录相关
		self.loginThread = None
		
	#----------------------------------------------------------------------
	def onFrontConnected(self):
		"""服务器连接"""
		self.connectionStatus = True
		
		log = VtLogData()
		log.gatewayName = self.gatewayName
		log.logContent = u'交易服务器连接成功'
		self.gateway.onLog(log)
		
		self.login()
	
	#----------------------------------------------------------------------
	def onFrontDisconnected(self, n):
		"""服务器断开"""
		self.connectionStatus = False
		self.loginStatus = False
		self.gateway.tdConnected = False
		
		log = VtLogData()
		log.gatewayName = self.gatewayName
		log.logContent = u'交易服务器连接断开'
		self.gateway.onLog(log)
	
	#----------------------------------------------------------------------
	def onRspUserLogin(self, data, error, n, last):
		"""登陆回报"""
		# 如果登录成功，推送日志信息
		if error['ErrorID'] == 0:
			self.seatID = str(data['SeatNo'])
			self.tradeCode = str(data['tradeCode'])
			
			self.loginStatus = True
			self.gateway.tdConnected = True
			
			log = VtLogData()
			log.gatewayName = self.gatewayName
			log.logContent = u'交易服务器登录完成'
			self.gateway.onLog(log)
			
			# 重新订阅之前订阅的合约
			for subscribeReq in self.subscribedSymbols:
				self.subscribe(subscribeReq)
							
			# 查询合约信息
			self.reqID += 1
			self.reqQryInstrument({}, self.reqID)
			
			# 启动查询
			self.gateway.startQuery()

		# 否则，推送错误信息
		else:
			err = VtErrorData()
			err.gatewayName = self.gatewayName
			err.errorID = error['ErrorID']
			err.errorMsg = error['ErrorMsg'].decode('gbk')
			self.gateway.onError(err)
			
			if error['ErrorID'] == -8:
				self.login()
	
	#----------------------------------------------------------------------
	def onRspUserLogout(self, data, error, n, last):
		"""登出回报"""
		# 如果登出成功，推送日志信息
		if error['ErrorID'] == 0:
			self.loginStatus = False
			self.gateway.tdConnected = False
			
			log = VtLogData()
			log.gatewayName = self.gatewayName
			log.logContent = u'交易服务器登出完成'
			self.gateway.onLog(log)
				
		# 否则，推送错误信息
		else:
			err = VtErrorData()
			err.gatewayName = self.gatewayName
			err.errorID = error['ErrorID']
			err.errorMsg = error['ErrorMsg'].decode('gbk')
			self.gateway.onError(err)
	
	#----------------------------------------------------------------------
	def onNtyMktStatus(self, data, error, n, last):
		"""更新市场状态"""
		pass
	
	#----------------------------------------------------------------------
	def onRspOrderInsert(self, data, error, n, last):
		"""发单错误（柜台）"""
		if error['ErrorID']:
			err = VtErrorData()
			err.gatewayName = self.gatewayName
			err.errorID = error['ErrorID']
			err.errorMsg = error['ErrorMsg'].decode('gbk')
			self.gateway.onError(err)
	
	#----------------------------------------------------------------------
	def onRspOrderAction(self, data, error, n, last):
		"""撤单错误（柜台）"""
		if error['ErrorID']:
			err = VtErrorData()
			err.gatewayName = self.gatewayName
			err.errorID = error['ErrorID']
			err.errorMsg = error['ErrorMsg'].decode('gbk')
			self.gateway.onError(err)
	   
	#----------------------------------------------------------------------
	def onRspQryOrder(self, data, error, n, last):
		""""""
		if not self.gateway.orderInited:
			self.gateway.orderInited = True
			
			log = VtLogData()
			log.gatewayName = self.gatewayName
			log.logContent = u'委托查询完成'
			self.gateway.onLog(log)
		
		# 更新最大报单编号
		newref = data['localOrderNo']
		self.orderRef = max(self.orderRef, int(newref))
		
		# 创建报单数据对象
		order = VtOrderData()
		order.gatewayName = self.gatewayName
		
		# 保存代码和报单号
		order.symbol = data['instID']
		order.exchange = EXCHANGE_SGE
		order.vtSymbol = order.symbol
		
		order.orderID = data['localOrderNo']
		
		# 方向
		if data['buyOrSell'] == '0':
			order.direction = DIRECTION_LONG
		elif data['buyOrSell'] == '1':
			order.direction = DIRECTION_SHORT
		else:
			order.direction = DIRECTION_UNKNOWN
			
		# 开平
		if data['offsetFlag'] == '0':
			order.offset = OFFSET_OPEN
		elif data['offsetFlag'] == '1':
			order.offset = OFFSET_CLOSE
		else:
			order.offset = OFFSET_UNKNOWN
			
		# 状态
		if data['status'] == '5':
			order.status = STATUS_ALLTRADED
		elif data['status'] == '6':
			order.status = STATUS_PARTTRADED
		elif data['status'] == '3':
			order.status = STATUS_NOTTRADED
		elif data['status'] == '4' or data['status'] == '7':	# 全部撤销和部成部撤
			order.status = STATUS_CANCELLED
		else:
			order.status = STATUS_UNKNOWN
		
		# CTP的报单号一致性维护需要基于frontID, sessionID, orderID三个字段
		# 但在本接口设计中，已经考虑了CTP的OrderRef的自增性，避免重复
		# 唯一可能出现OrderRef重复的情况是多处登录并在非常接近的时间内（几乎同时发单）
		# 考虑到VtTrader的应用场景，认为以上情况不会构成问题
		order.vtOrderID = '.'.join([self.gatewayName, order.orderID])
		
		# 价格、报单量等数值
		order.price = data['price']
		order.totalVolume = data['amount']
		order.tradedVolume = data['matchQty']
		order.orderTime = data['entrustTime']
		order.cancelTime = data['cancelTime']
		
		# 推送
		self.gateway.onOrder(order)
	
	#----------------------------------------------------------------------
	def onRspQryTrade(self, data, error, n, last):
		""""""
		if not self.gateway.tradeInited:
			self.gateway.tradeInited = True
			
			log = VtLogData()
			log.gatewayName = self.gatewayName
			log.logContent = u'成交查询完成'
			self.gateway.onLog(log)
		
		# 创建报单数据对象
		trade = VtTradeData()
		trade.gatewayName = self.gatewayName
		
		# 保存代码和报单号
		trade.symbol = data['instID']
		trade.exchange = EXCHANGE_SGE
		trade.vtSymbol = trade.symbol
		
		trade.tradeID = data['matchNo']
		trade.vtTradeID = '.'.join([self.gatewayName, trade.tradeID])
		
		trade.orderID = data['localOrderNo']
		trade.vtOrderID = '.'.join([self.gatewayName, trade.orderID])
		
		# 方向
		trade.direction = directionMapReverse.get(data['buyOrSell'], '')
			
		# 开平
		trade.offset = offsetMapReverse.get(data['offSetFlag'], '')
			
		# 价格、报单量等数值
		trade.price = data['price']
		trade.volume = data['volume']
		trade.tradeTime = data['matchTime']
		
		# 推送
		self.gateway.onTrade(trade)
	
	#----------------------------------------------------------------------
	def onRspQryInvestorPosition(self, data, error, n, last):
		"""持仓查询回报"""
		# 过滤一些空的数据
		if data['instID']:
			# 黄金API推送的持仓数据把多空仓放在了一条中，需要分离
			longPos = VtPositionData()
			longPos.gatewayName = self.gatewayName
			longPos.symbol = data['instID']
			longPos.vtSymbol = longPos.symbol
			longPos.direction = DIRECTION_LONG
			longPos.frozen = data['longPosiFrozen']
			longPos.position = data['longPosiVol']
			longPos.ydPosition = data['lastLong']
			longPos.price = data['longPosiAvgPrice']
			longPos.vtPositionName = '.'.join([longPos.vtSymbol, longPos.direction])
			self.gateway.onPosition(longPos)
			
			shortPos = VtPositionData()
			shortPos.gatewayName = self.gatewayName
			shortPos.symbol = data['instID']
			shortPos.vtSymbol = shortPos.symbol
			shortPos.direction = DIRECTION_SHORT
			shortPos.frozen = data['shortPosiFrozen']
			shortPos.position = data['shortPosiVol']
			shortPos.ydPosition = data['lastShort']
			shortPos.price = data['shortPosiAvgPrice']
			shortPos.vtPositionName = '.'.join([shortPos.vtSymbol, shortPos.direction])
			self.gateway.onPosition(shortPos)
	
	#----------------------------------------------------------------------
	def onRspQryTradingAccount(self, data, error, n, last):
		"""资金账户查询回报"""
		account = VtAccountData()
		account.gatewayName = self.gatewayName
		
		# 账户代码
		account.accountID = 'sge_account'   # API不提供该字段，自行定义
		account.vtAccountID = '.'.join([self.gatewayName, account.accountID])
		
		# 数值相关
		account.available = data['availCap']
		account.commission = data['totalFee']
		account.margin = data['posiMargin']
		
		# 推送
		self.gateway.onAccount(account)
	
	#----------------------------------------------------------------------
	def onRspQryInstrument(self, data, error, n, last):
		"""合约查询回报"""
		contract = VtContractData()
		contract.gatewayName = self.gatewayName

		contract.symbol = data['instID']
		contract.exchange = EXCHANGE_SGE	# 交易所只有金交所
		
		# 合约类型分为现货、延期、未知
		if data['marketID'] == '00':
			contract.productClass = PRODUCT_SPOT
		elif data['marketID'] == '10':
			contract.productClass = PRODUCT_DEFER
		else:
			contract.productclass = PRODUCT_UNKNOWN
		
		contract.vtSymbol = contract.symbol
		contract.name = data['name'].decode('GBK')
		
		# 合约数值
		contract.size = data['unit']
		contract.priceTick = data['tick']
		
		# 推送，考虑到只对T+D类带杠杆的产品感兴趣，API里默认过滤了现货
		if data['marketID'] == '10':
			self.gateway.onContract(contract)
		
		if last:
			log = VtLogData()
			log.gatewayName = self.gatewayName
			log.logContent = u'交易合约信息获取完成'
			self.gateway.onLog(log)
	
	#----------------------------------------------------------------------
	def onRtnDepthMarketData(self, data):
		"""行情推送"""
		tick = VtTickData()
		tick.gatewayName = self.gatewayName
		
		tick.symbol = data['InstID']
		tick.vtSymbol = tick.symbol
		
		tick.lastPrice = data['Last']
		tick.volume = data['Volume']
		tick.openInterest = data['OpenInt']
		tick.time = data['QuoteTime']
		tick.date = data['QuoteDate']
		
		tick.openPrice = data['Open']
		tick.highPrice = data['High']
		tick.lowPrice = data['Low']
		tick.preClosePrice = data['PreClose']
		
		tick.upperLimit = data['highLimit']
		tick.lowerLimit = data['lowLimit']
		
		# CTP只有一档行情
		tick.bidPrice1 = data['Bid1']
		tick.bidPrice2 = data['Bid2']
		tick.bidPrice3 = data['Bid3']
		tick.bidPrice4 = data['Bid4']
		tick.bidPrice5 = data['Bid5']
		
		tick.askPrice1 = data['Ask1']
		tick.askPrice2 = data['Ask2']
		tick.askPrice3 = data['Ask3']
		tick.askPrice4 = data['Ask4']
		tick.askPrice5 = data['Ask5']
		
		tick.bidVolume1 = data['BidLot1']
		tick.bidVolume2 = data['BidLot2']
		tick.bidVolume3 = data['BidLot3']
		tick.bidVolume4 = data['BidLot4']
		tick.bidVolume5 = data['BidLot5']
		
		tick.askVolume1 = data['AskLot1']
		tick.askVolume2 = data['AskLot2']
		tick.askVolume3 = data['AskLot3']
		tick.askVolume4 = data['AskLot4']
		tick.askVolume5 = data['AskLot5']
		
		self.gateway.onTick(tick)
		
	#----------------------------------------------------------------------
	def onRtnOrder(self, data):
		"""报单回报"""
		# 更新最大报单编号
		newref = data['localOrderNo']
		self.orderRef = max(self.orderRef, int(newref))
		
		# 创建报单数据对象
		order = self.orderDict.get(int(newref), VtOrderData())
		order.gatewayName = self.gatewayName
		order.exchange = EXCHANGE_SGE
		order.orderID = data['localOrderNo']
		
		# 状态
		if data['status'] == '5':
			order.status = STATUS_ALLTRADED
		elif data['status'] == '6':
			order.status = STATUS_PARTTRADED
		elif data['status'] == '3':
			order.status = STATUS_NOTTRADED
		elif data['status'] == '4' or data['status'] == '7':	# 全部撤销和部成部撤
			order.status = STATUS_CANCELLED
		else:
			order.status = STATUS_UNKNOWN
		
		# 推送
		self.gateway.onOrder(order)
		
	#----------------------------------------------------------------------
	def onForceLogout(self, data):
		"""强制登出推送"""
		self.gateway.onLog(u'被强制登出')
	
	#----------------------------------------------------------------------
	def onRtnTrade(self, data):
		"""成交回报"""
		# 创建报单数据对象
		trade = VtTradeData()
		trade.gatewayName = self.gatewayName
		
		# 保存代码和报单号
		trade.symbol = data['instID']
		trade.exchange = EXCHANGE_SGE
		trade.vtSymbol = trade.symbol
		
		trade.tradeID = data['matchNo']
		trade.vtTradeID = '.'.join([self.gatewayName, trade.tradeID])
		
		trade.orderID = data['localOrderNo']
		trade.vtOrderID = '.'.join([self.gatewayName, trade.orderID])
		
		# 方向
		trade.direction = directionMapReverse.get(data['buyOrSell'], '')
			
		# 开平
		trade.offset = offsetMapReverse.get(data['offSetFlag'], '')
			
		# 价格、报单量等数值
		trade.price = data['price']
		trade.volume = data['volume']
		trade.tradeTime = data['matchTime']
		
		# 推送
		self.gateway.onTrade(trade)
		
		# 计算还原Order状态，并推送
		order = self.orderDict.get(int(trade.orderID), None)
		if order:
			order.tradedVolume = order.tradedVolume + trade.volume
			
			if order.tradedVolume == order.totalVolume:
				order.status = STATUS_ALLTRADED
			else:
				order.status = STATUS_PARTTRADED
				
		self.gateway.onOrder(order)
	
	#----------------------------------------------------------------------
	def onErrRtnOrderInsert(self, data, error):
		"""发单错误回报（交易所）"""
		if error['ErrorID']:
			err = VtErrorData()
			err.gatewayName = self.gatewayName
			err.errorID = error['ErrorID']
			err.errorMsg = error['ErrorMsg'].decode('gbk')
			self.gateway.onError(err)
		
	#----------------------------------------------------------------------
	def onErrRtnOrderAction(self, data, error):
		"""撤单错误回报（交易所）"""
		if error['ErrorID']:
			err = VtErrorData()
			err.gatewayName = self.gatewayName
			err.errorID = error['ErrorID']
			err.errorMsg = error['ErrorMsg'].decode('gbk')
			self.gateway.onError(err)

	#----------------------------------------------------------------------
	def onRspQryClientStorage(self, data, error, n, last):
		""""""
		pass
		
	#----------------------------------------------------------------------
	def onRspSubMarketData(self, data, error, n, last):
		""""""
		pass
	
	#----------------------------------------------------------------------
	def connect(self, accountID, password, address):
		"""初始化连接"""
		self.accountID = accountID
		self.password = password
		self.address = address
		
		# 如果尚未建立服务器连接，则进行连接
		if not self.connectionStatus:
			self.createGoldTraderApi()
			
			# 注册服务器地址
			self.registerFront(self.address)

			# 初始化连接，成功会调用onFrontConnected
			self.init(False)
			self.connectionStatus = True
			
			# 金仕达接口第一次连接不会调用onFrontConnected（只有断线重连才会），直接登录
			self.login()
			
		# 若已经连接但尚未登录，则进行登录
		else:
			if not self.loginStatus:
				self.login()
	
	#----------------------------------------------------------------------
	def login(self):
		"""连接服务器"""
		# 如果填入了用户名密码等，则登录
		if self.accountID and self.password:
			req = {}
			req['accountID'] = self.accountID
			req['password'] = self.password
			req['loginType'] = 1
			self.reqID += 1
			self.reqUserLogin(req, self.reqID)
		
	#----------------------------------------------------------------------
	def qryAccount(self):
		"""查询账户"""
		self.reqID += 1
		self.reqQryTradingAccount({}, self.reqID)
		
	#----------------------------------------------------------------------
	def qryPosition(self):
		"""查询持仓"""
		self.reqID += 1
		self.reqQryInvestorPosition({}, self.reqID)
	
	#----------------------------------------------------------------------
	def getTrade(self):
		"""查询成交"""
		self.reqID += 1
		self.reqQryTrade({}, self.reqID)
	
	#----------------------------------------------------------------------
	def getOrder(self):
		"""查询委托"""
		self.reqID += 1
		self.reqQryOrder({}, self.reqID)
	
	#----------------------------------------------------------------------
	def sendOrder(self, orderReq):
		"""发单"""
		self.reqID += 1
		self.orderRef += 1
		
		req = {}
		
		req['instID'] = orderReq.symbol
		req['marketID'] = '10'
		
		req['price'] = orderReq.price
		req['amount'] = orderReq.volume
		
		# 下面如果由于传入的类型本接口不支持，则会返回空字符串
		try:
			req['buyOrSell'] = directionMap[orderReq.direction]
			req['offsetFlag'] = offsetMap[orderReq.offset]
		except KeyError:
			return ''
		
		strOrderID = generateStrLocalID(self.orderRef)
		req['LocalOrderNo'] = strOrderID
		req['seatID'] = self.seatID
		req['tradeCode'] = self.tradeCode
		
		self.reqOrderInsert(req, self.reqID)
		
		# 返回订单号（字符串），便于某些算法进行动态管理
		vtOrderID = '.'.join([self.gatewayName, strOrderID])
		
		# 保存请求到本地，用于在收到回报时查询
		# 金仕达黄金API的onRtnOrder只推送很有限的几个数据，因此整个数据需要自己还原
		order = VtOrderData()
		order.gatewayName = self.gatewayName
		order.symbol = orderReq.symbol
		order.vtSymbol = orderReq.symbol
		order.exchange = EXCHANGE_SGE
		order.orderID = strOrderID
		order.vtOrderID = strOrderID
		order.direction = orderReq.direction
		order.offset = orderReq.offset
		order.price = orderReq.price
		order.totalVolume = orderReq.volume
		order.orderTime = time.strftime('%H:%M:%S')   # 保存委托时间
		self.orderDict[self.orderRef] = order
		
		return vtOrderID
	
	#----------------------------------------------------------------------
	def cancelOrder(self, cancelOrderReq):
		"""撤单"""
		self.reqID += 1

		req = {}
		req['localOrderNo'] = cancelOrderReq.orderID
		req['marketID'] = '10'  # API默认只允许交易T+D延期
		
		self.reqOrderAction(req, self.reqID)
	
	#----------------------------------------------------------------------
	def subscribe(self, subscribeReq):
		"""订阅行情"""
		# 黄金API的订阅传入的参数不是具体交易合约代码，而是类型代码
		# 考虑到只希望交易T+D，这里直接传入'10'
		self.subscribeMarketData('10')
	
	#----------------------------------------------------------------------
	def close(self):
		"""关闭"""
		self.exit()


#----------------------------------------------------------------------
def generateStrLocalID(localID):
	"""把整数的本地委托号转化为字符串"""
	return str(localID).rjust(12, '0')

